﻿#include "OiPCH.hpp"
#include "Util/OiOPC.hpp"
#include "Util/OiPLC.hpp"
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlDriver>
#include <QtSql/QSqlError>
#include <QtSql/QSqlRecord>

namespace Oi
{
    namespace PLScannerCore
    {
        bool PLScannerOutput::saveToSys(const WorkResult::Result& r, const QString name)
        {
            auto writer = OutputWriterSystem::instance()->writer(name);

            if (writer)
            {
                return writer->output(r);
            }
            else
            {
                return false;
            }
        }

        bool PLScannerOutput::saveToSys(const DataRow& r, const QString name)
        {
            auto writer = OutputWriterSystem::instance()->writer(name);

            if (writer)
            {
                return writer->output(r);
            }
            else
            {
                return false;
            }
        }

        bool PLScannerOutput::saveToSys(const FixedValueRow& r, const QString name)
        {
            auto writer = OutputWriterSystem::instance()->writer(name);

            if (writer)
            {
                return writer->output(r);
            }
            else
            {
                return false;
            }
        }

        bool PLScannerOutput::heartbeat(int value, const QString name)
        {
            auto writer = OutputWriterSystem::instance()->writer(name);

            if (writer)
            {
                return writer->heartbeat(value);
            }
            else
            {
                return false;
            }
        }

        bool PLScannerOutput::saveToSys(const QString n, double v, int r, const QString name)
        {
            auto writer = OutputWriterSystem::instance()->writer(name);

            if (writer)
            {
                return writer->output(n, v, r);
            }
            else
            {
                return false;
            }
        }

        class OutputWriterSystemImpl : public Impl<OutputWriterSystem>
        {
        public:
            QMap<QString, QSharedPointer<OutputWriter>> _writer;
        };

        class outputWriter_Linglong_Database : public OutputWriter
        {
        public:
            outputWriter_Linglong_Database();
            ~outputWriter_Linglong_Database();

        public:
            bool ready();
            bool output(const DataRow&);
            bool output(const FixedValueRow&);
            bool output(const WorkResult::Result&);
            bool output(const QString name, const double, const int);
            bool heartbeat(int);

        public:
            QSqlDatabase _db;
            QString _tb;
            QString _tb_fixed;
        };

        outputWriter_Linglong_Database::outputWriter_Linglong_Database()
        {
            _tb = "plscanner_data";
            _tb_fixed = "plscanner_fixed_data";
            _db = QSqlDatabase::addDatabase("QODBC", "LinglongLocal");
            _db.setHostName("127.0.0.1");
            _db.setPort(3306);
            _db.setDatabaseName("test");
            _db.setUserName("thicknesslocal");
            _db.setPassword("ch123456");
         
            bool ret = _db.open();
            if (ret)
            {
                QSqlQuery query(_db);
                QDateTime lastTime = QDateTime::currentDateTime();//系统当前时间
                QDateTime aweekAgo = lastTime.addDays(-7);//参数是可以为负数的，负数就是获取以前的时间，正数就是获取未来的时间

                QString deleteSql = QString("delete from plscanner.'%1' where datetime < '%2'").arg(_tb).arg(aweekAgo.toString("yyyy-MM-dd hh:mm:ss"));
                query.exec(deleteSql);
                OiWarning() << "Linglong_Local_DB ok:" ;
            }
            else
            {
                OiWarning() << "Linglong_Local_DB open:" << _db.lastError();
            }
        }

        outputWriter_Linglong_Database::~outputWriter_Linglong_Database()
        {
            _db.close();
        }

        bool outputWriter_Linglong_Database::ready()
        {
            return _db.isOpen();
        }

        bool outputWriter_Linglong_Database::output(const WorkResult::Result& r)
        {
            return true;
        }

        bool outputWriter_Linglong_Database::output(const QString name, const double, const int)
        {
            return true;
        }

        bool outputWriter_Linglong_Database::output(const DataRow& data)
        {
            if (_db.isOpen())
            {
                bool ret = _db.open();
                if (!ret)
                {
                    OiWarning() << "Linglong_Local_DB output: open failed";
                    return false;
                }
            }

            int resultValue = 0;
            if (data.result == WorkResult::RC_Success)
            {
                resultValue = 0;
            }
            else if (data.result == WorkResult::RC_Warning)
            {
                resultValue = 1;
            }
            else 
            {
                resultValue = 2;
            }

            QSqlQuery query(_db);

            QString sysid = "";
            QString isread = "N";

            if (query.exec("select sysid from mes_systemid where id = (select MAX(id) from mes_systemid)"))
            {
                if (query.next())
                {
                    sysid = query.value(0).toString();
                }
                else
                {
                    OiWarning() << "Linglong_Local_DB:" << "No item in mes_systemid";
                }
            }
            else
            {
                OiWarning() << "Linglong_Local_DB:" << query.lastError();
            }
            QString queryString = QString("INSERT INTO plscanner.%1 (result, datetime, formula, user, team, width, width_EL, thickness1, thickness2, thickness3, thickness4,"
                "widthTol, widthStd, thickness1Tol, thickness1Std, thickness2Tol, thickness2Std, thickness3Tol, thickness3Std, thickness4Tol, thickness4Std, thickness1Dif,  thickness2Dif,  thickness3Dif,  thickness4Dif,  EdgeThicknessDif,isread,sysid) "
                "VALUES(%2, '%3', '%4', '%5', %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25 ,'%26', '%27', '%28','%29')")
                .arg(_tb)
                .arg(resultValue)
                .arg(data.datetime.toString("yyyy-MM-dd hh:mm:ss"))
                .arg(data.formula)
                .arg(data.user)
                .arg(data.team)
                .arg(data.width)
                .arg(data.width)
                .arg(data.thickness1)
                .arg(data.thickness2)
                .arg(data.thickness3)
                .arg(data.thickness4)
                .arg(data.widthErr)
                .arg(data.widthStd)
                .arg(data.thickness1Err)
                .arg(data.thickness1Std)
                .arg(data.thickness2Err)
                .arg(data.thickness2Std)
                .arg(data.thickness3Err)
                .arg(data.thickness3Std)
                .arg(data.thickness4Err)
                .arg(data.thickness4Std)
                .arg(data.thickness1Dif)
                .arg(data.thickness2Dif)
                .arg(data.thickness3Dif)
                .arg(data.thickness4Dif)
                .arg(data.edgeThicknessDif)
                .arg(isread)
                .arg(sysid);

            query.prepare(queryString);

            bool ret = query.exec();

            if (ret)
            {
             
            }
            else
            {
                OiWarning() << query.lastError();
                OiWarning() << queryString;
            }

            return ret;
        }

        bool outputWriter_Linglong_Database::output(const FixedValueRow& data)
        {
            if (!_db.open())
            {
                return false;
            }

            int resultValue = 0;
            if (data.result == WorkResult::RC_Success)
            {
                resultValue = 0;
            }
            else if (data.result == WorkResult::RC_Warning)
            {
                resultValue = 1;
            }
            else
            {
                resultValue = 2;
            }

            QSqlQuery query(_db);

            QString sysid = "";
            QString isread = "N";

            if (query.exec("select sysid from mes_systemid where id = (select MAX(id) from mes_systemid)"))
            {
                if (query.next())
                {
                    sysid = query.value(0).toString();
                }
                else
                {
                    OiWarning() << "No item in mes_systemid";
                }
            }
            else
            {
                OiWarning() << query.lastError();
            }

            QString queryString = QString("INSERT INTO %1 (result, datetime, formula, user, team, thicknessTol, thicknessStd, thicknessValue, sysid, isread) "
                "VALUES(%2, '%3', '%4', '%5', %6, %7,  %8, %9, '%10', '%11')")
                .arg(_tb_fixed)
                .arg(resultValue)
                .arg(data.datetime.toString("yyyy-MM-dd hh:mm:ss"))
                .arg(data.formula)
                .arg(data.user)
                .arg(data.team)
                .arg(data.errValue)
                .arg(data.stdValue)
                .arg(data.value)
                .arg(sysid)
                .arg(isread);

            query.prepare(queryString);

            bool ret = query.exec();

            if (ret)
            {

            }
            else
            {
                OiWarning() << query.lastError();
                OiWarning() << queryString;
            }

            return ret;
        }

        bool outputWriter_Linglong_Database::heartbeat(int)
        {
            return true;
        }

        class outputWriter_OPC : public OutputWriter
        {
        public:
            outputWriter_OPC();
            ~outputWriter_OPC();

        public:
            bool ready();
            bool output(const DataRow&);
            bool output(const FixedValueRow&);
            bool output(const WorkResult::Result&);
            bool output(const QString name, const double, const int);
            bool heartbeat(int);
        };

        outputWriter_OPC::outputWriter_OPC()
        {
            OPCTask::instance();
        }

        outputWriter_OPC::~outputWriter_OPC()
        {
            OPCTask::instance()->exit();
        }

        bool outputWriter_OPC::ready()
        {
            return OPCTask::instance()->isRunning();
        }

        bool outputWriter_OPC::output(const WorkResult::Result& r)
        {
            return OPCTask::instance()->write(r);
        }

        bool outputWriter_OPC::output(const QString name, const double v, const int r)
        {
            return OPCTask::instance()->write(name, v, r);
        }

        bool outputWriter_OPC::output(const DataRow&)
        {
            return true;
        }

        bool outputWriter_OPC::output(const FixedValueRow&)
        {
            return true;
        }

        bool outputWriter_OPC::heartbeat(int h)
        {
            return OPCTask::instance()->heartbeat(h);
        }

        class outputWriter_SL_PLC : public OutputWriter
        {
        public:
            outputWriter_SL_PLC();
            ~outputWriter_SL_PLC();

        public:
            bool ready();
            bool output(const DataRow&);
            bool output(const FixedValueRow&);
            bool output(const WorkResult::Result&);
            bool output(const QString name, const double, const int);
            bool heartbeat(int);
        };

        outputWriter_SL_PLC::outputWriter_SL_PLC()
        {
            PLCTask::instance();
        }

        outputWriter_SL_PLC::~outputWriter_SL_PLC()
        {
            PLCTask::instance()->exit();
        }

        bool outputWriter_SL_PLC::ready()
        {
            return PLCTask::instance()->isRunning();
        }

        bool outputWriter_SL_PLC::output(const WorkResult::Result& r)
        {
            return false;
        }

        bool outputWriter_SL_PLC::output(const QString name, const double v, const int r)
        {
            return false;
        }

        bool outputWriter_SL_PLC::output(const DataRow& data)
        {
            ProductParams params;
            PLCTask::instance()->writeResult(data);
            return true;
        }

        bool outputWriter_SL_PLC::output(const FixedValueRow& data)
        {
            //ProductParams params;

            //PLCTask::instance()->writeResult(params);
            return true;
        }

        bool outputWriter_SL_PLC::heartbeat(int h)
        {
            return false;
        }

        QSharedPointer<OutputWriter> OutputWriter::create(QString name)
        {
            if (name == "OPC")
            {
                return  QSharedPointer<OutputWriter>(new outputWriter_OPC());
            }
            else if (name == "Linglong_Local_DB")
            {
                return  QSharedPointer<OutputWriter>(new outputWriter_Linglong_Database());
            }
            else if (name == "SL_PLC")
            {
                return  QSharedPointer<OutputWriter>(new outputWriter_SL_PLC());
            }
            return QSharedPointer<OutputWriter>();
        }

        OutputWriterSystem::OutputWriterSystem()
        {
            OI_I(OutputWriterSystem);
        }

        QSharedPointer<OutputWriter> OutputWriterSystem::writer(QString name)
        {
            OI_F(OutputWriterSystem);
            if(d->_writer.contains(name))
            {
                return d->_writer[name];
            }
            else
            {
                auto writer = OutputWriter::create(name);
                if(writer)
                {
                    d->_writer[name] = writer;
                    return writer;
                }
                return QSharedPointer<OutputWriter>();
            }
        }


        void OutputWriterSystem::clear()
        {
            OI_F(OutputWriterSystem);
            d->_writer.clear();
        }

        void OutputWriterSystem::addWriter(QString name, QSharedPointer<OutputWriter> writer)
        {
            OI_F(OutputWriterSystem);

            d->_writer[name] = writer;
        }

        OutputWriterSystem* OutputWriterSystem::instance()
        {
            static OutputWriterSystem system;
            return &system;
        }

    }
}
